package com.iring.service.common.impl;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.iring.domain.config.prop.LocalConfigProperties;
import com.iring.domain.config.prop.VOSCustomerProperties;
import com.iring.dao.common.ConsumptionDao;
import com.iring.dao.common.UserDao;
import com.iring.dao.vos.CommonVosDao;
import com.iring.dao.vos.UserVosDao;
import com.iring.domain.common.AmountTask;
import com.iring.domain.common.User;
import com.iring.domain.sms.SMS;
import com.iring.domain.vos.BaseBack;
import com.iring.domain.vos.customer.Customer;
import com.iring.domain.vos.customer.CustomerAdd;
import com.iring.domain.vos.customer.UserRequest;
import com.iring.exception.ParamInvalidException;
import com.iring.exception.config.ErrorEnum;
import com.iring.service.common.DeviceService;
import com.iring.service.common.LogService;
import com.iring.service.common.PayAmountService;
import com.iring.service.common.UserService;
import com.iring.service.sms.MessageService;
import com.iring.util.common.CommonUtil;
import com.iring.util.common.ImgUtil;
import com.iring.util.common.IringHandler;
import com.iring.util.common.IringThread;
import com.iring.util.common.PasswordEncoderUtil;
import com.iring.util.common.StringUtil;
import com.iring.vo.sms.SMSCheckVO;
import com.iring.vo.sms.SMSSendVO;
import com.iring.vo.user.AlarmVO;
import com.iring.vo.user.CheckUsernameVO;
import com.iring.vo.user.ImgVO;
import com.iring.vo.user.LoginVO;
import com.iring.vo.user.ModPassVO;
import com.iring.vo.user.PasswordVO;
import com.iring.vo.user.UserInfoVO;
import com.iring.vo.user.UserUpdateVO;
/*
 * @author wanggan
 */
@Service

public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    UserDao userDao;

    @Autowired
    ConsumptionDao consumptionDao;

    @Autowired
    PayAmountService payAmountService;

    @Autowired
    LocalConfigProperties localUserProperties;

    @Autowired
    VOSCustomerProperties vosCustomerProperties;

    @Autowired
    MessageService messageService;

    @Autowired
    UserVosDao userVosDao;

    @Autowired
    CommonVosDao commonVosDao;

    @Autowired
    PasswordEncoderUtil encoder;

    @Autowired
    DeviceService deviceService;

    @Autowired
    LogService logService;

    @Autowired
    CommonUtil commonUtil;

    private void checkStringParam(String str, String name) {
        if (str == null || str.trim()
                .equals("")) {
            throw new ParamInvalidException(name + " is null");
        }
    }

    private void checkPasswordParam(String password, String name) {
        if (StringUtil.isEmpty(password)) {
            throw new ParamInvalidException(name + " is null");
        } else if (password.length() < 6) {
            throw new ParamInvalidException(name + " length must be bigger than 6");
        } else if (password.length() > 32) {
            throw new ParamInvalidException(name + " length must be less than 32");
        }
    }

    private void checkCodeParam(String code) {
        if (code == null || code.trim()
                .equals("")) {
            throw new ParamInvalidException("code is null");
        } else if (code.length() <= 3) {
            throw new ParamInvalidException("invalid code length");
        }
    }

    private void checkUsernameParam(String username){
        checkStringParam(username, "username");

        Boolean isEmail = commonUtil.checkEmail(username);
        if(!isEmail){
            throw new ParamInvalidException("invalid username format");
        }
    }

    private void checkPhoneParam(String contactPhonenum){
        checkStringParam(contactPhonenum, "contactPhonenum");

        Boolean isphone = commonUtil.checkPhone(contactPhonenum);
        if(!isphone){
            throw new ParamInvalidException("invalid phone number format");
        }
    }



    /**
     * @param username 需要判断的用户名
     * @return 用户名不存在返回true 存在返回false
     */
    private Boolean isUsernameAvailable(String username) {
        checkUsernameParam(username);
        User user = userDao.findByUsername(username);
        if (null == user) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public User checkUsername(CheckUsernameVO checkUsernameVO, String randomImage) {
        String username = checkUsernameVO.getUsername();
        checkUsernameParam(username);

        String imgcode = checkUsernameVO.getImgcode();
        checkStringParam(imgcode, "imgcode");
        if (!randomImage.equalsIgnoreCase(imgcode)) {
            throw new ParamInvalidException(ErrorEnum.INVALID_IMAGE_CODE);
        }
        User user = userDao.findByUsername(username);
        if(null == user){
            throw new ParamInvalidException(ErrorEnum.INVALID_USERNAME);
        }
        user.setContactPhonenum(commonUtil.dealContactPhoneNumber(user.getContactPhonenum()));
        return user;
    }

    /**
     * @see UserService#checkUsername(String)
     */
    @Override
    public Boolean checkUsername(String username) {

        checkUsernameParam(username);
        if (!isUsernameAvailable(username)) {
            // 如果当前用户名已经存在
            return Boolean.FALSE;
        }
        // 判断用户是否在vos注册,可用返回true
        Boolean isVosUsernameAvailable = isVosUsernameAvailable(username);
        if (isVosUsernameAvailable) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * @see UserService#sendCode(SMSSendVO)
     */
    @Override
    public Boolean sendCode(SMSSendVO smsSendVO) {
        String countryCode = smsSendVO.getCountryCode();
        checkStringParam(countryCode, "countryCode");

        String contactPhonenum = smsSendVO.getContactPhonenum();
        checkPhoneParam(contactPhonenum);

        User user = userDao.findByContactPhonenum(countryCode + "-" + contactPhonenum);
        if (null == user) {// 如果用户为空,创建一个
            SMS sms = new SMS(contactPhonenum, countryCode);
            Boolean isSend = messageService.sendCode(sms);
            if(isSend){
                return isSend;
            }else {
                throw new ParamInvalidException(ErrorEnum.NETWORK_EXCEPTION);
            }
        } else {// 如果存在抛出异常
            throw new ParamInvalidException(ErrorEnum.INVALID_CONTACT_PHONENUM);
        }
    }

    /**
     * @see UserService#addUser(UserInfoVO)
     */
    @Override
    public User addUser(UserInfoVO userInfoVO) {
        String username = userInfoVO.getUsername();
        checkUsernameParam(username);

        String password = userInfoVO.getPassword();
        checkPasswordParam(password, "password");

        String countryCode = userInfoVO.getCountryCode();
        checkStringParam(countryCode, "countryCode");

        String contactPhonenum = userInfoVO.getContactPhonenum();
        checkPhoneParam(contactPhonenum);


        String code = userInfoVO.getCode();
        checkCodeParam(code);

        Boolean isUse = checkUsername(username);
        if (!isUse) {
            throw new ParamInvalidException(ErrorEnum.INVALID_USERNAME);
        }

        User user = userDao.findByContactPhonenum(countryCode + "-" + contactPhonenum);
        if (user != null) {
            throw new ParamInvalidException(ErrorEnum.INVALID_CONTACT_PHONENUM);
        }


        // 检查验证码是否正确
        SMS sms = new SMS(contactPhonenum, countryCode, code);
        messageService.checkCode(sms);
        // 创建vos和本地账号
        return createVosAndLocalUser(userInfoVO);

    }

    /**
     * @see UserService#checkPbxUserAccount(String, String)
     */
    @Override
    public Boolean checkPbxUserAccount(String username, String password) {
        checkUsernameParam(username);
        checkPasswordParam(password, "password");

        User user = userDao.findByUsername(username);
        if(null ==user) {
            return Boolean.FALSE;
        } else {
            return encoder.checkPassword(password, user.getPassword());
        }
    }

    /**
     * @see UserService#dealAmoutTask(String,String)
     */
    @Override
    public void dealAmoutTask(String username,String ip) {

        new Thread(new IringThread(new IringHandler() {
            @Override
            public void execute() {
                List<AmountTask> amountTask = payAmountService.findByUsername(username);
                if (amountTask.size() == 0) {// 如果不存在未完成的任务信息,结算金额
                    // 获取用户的账户信息并判断是否结算金额处理
                    Customer customer = userVosDao.getVosCustomer(new UserRequest(new String[]{username}));
                    if (customer instanceof Customer) {
                        // 更新账户余额
                            updateLocalUserRestAmouts(username, customer.getMoney(),ip);
                    }
                }
            }
        })).start();
    }

    /**
     * @see UserService#findUser(LoginVO)
     */
    @Override
    public User findUser(LoginVO loginVO) {
        String username = loginVO.getUsername();
        checkUsernameParam(username);

        String password = loginVO.getPassword();
        checkPasswordParam(password, "password");

        User user = userDao.findByUsername(username);
        if(null == user){
            return null;
        }
        if (encoder.checkPassword(loginVO.getPassword(), user.getPassword())) {
            return user;
        } else {
            return null;

        }
    }

    /**
     * 创建vos账户和本地账户
     *
     * @param userInfoVO {@link UserInfoVO}
     * @return {@link User}
     */
    private User createVosAndLocalUser(UserInfoVO userInfoVO) {
        // 请求vos,如果vos创建成功,则创建本地
        BaseBack baseBack = commonVosDao.createVosCustomer(createVosCustomer(userInfoVO));
        Integer retCode = baseBack.getRetCode();
        if(null == retCode){
            return null;
        }
        if (0.0 == retCode) {// 如果返回0,则创建成功
            User user = createLocalUser(userInfoVO);
            logger.info("add vos and local user success={}", user);
            return user;
        } else {
            logger.info("add vos user fail={}", baseBack);
            throw new ParamInvalidException(baseBack.getException());
        }
    }

    /**
     * 创建本地账户
     *
     * @param userInfoVO {@link UserInfoVO}
     * @return {@link User}
     */
    private User createLocalUser(UserInfoVO userInfoVO) {
        User user = new User();
        String username = userInfoVO.getUsername();
        user.setContact(username);
        user.setContactPhonenum(userInfoVO.getCountryCode() + "-" + userInfoVO.getContactPhonenum());
        user.setPostcode(vosCustomerProperties.getPostCode());
        user.setOrganization(vosCustomerProperties.getCompanyName());
        user.setAddress(vosCustomerProperties.getAddress());
        // 设置默认赠送余额1美元
        user.setRestAmounts(vosCustomerProperties.getMoney());
        user.setEmail(username);
        user.setUsername(username);
        user.setPassword(encoder.encodePassword(userInfoVO.getPassword()));
        user.setHeadPicture(localUserProperties.getHeadPicture());
        user.setAvailableAmountsAlarm(localUserProperties.getIsAlarm());
        user = userDao.save(user);
        return user;
    }

    /**
     * 创建vos的账户信息
     *
     * @param userInfoVO {@link UserInfoVO}
     * @return {@link Customer}
     */
    private Customer createVosCustomer(UserInfoVO userInfoVO) {
        CustomerAdd add = new CustomerAdd();
        String username = userInfoVO.getUsername();
        add.setAddress(vosCustomerProperties.getAddress());
        add.setCompanyName(vosCustomerProperties.getCompanyName());
        add.setEmail(username);
        add.setFax("0");
        add.setLinkMan(username);
        add.setPostCode(vosCustomerProperties.getPostCode());
        // 设置报表类型
        add.setReportType(vosCustomerProperties.getReportType());
        add.setTelephone(userInfoVO.getCountryCode() + "-" + userInfoVO.getContactPhonenum());

        Customer customer = new Customer();
        customer.setAccount(username);
        customer.setName(username);
        customer.setLimitMoney(vosCustomerProperties.getLimitMoney());
        customer.setMoney(vosCustomerProperties.getMoney());
        customer.setInfoCustomerAdditional(add);
        // 设置用户的费率组
        customer.setFeeRateGroup(vosCustomerProperties.getFeerateGroup());
        return customer;
    }

    /**
     * @param chPwdInfo 旧密码和新密码等信息
     * @param username  用户名
     * @return 用户名不存在返回205, 存在并原始密码正确返回true, 存在但密码错误抛出异常
     */
    @Override
    public Boolean changePassword(PasswordVO chPwdInfo, String username) {
        String oldPass = chPwdInfo.getOldpassword();
        checkPasswordParam(oldPass, "oldPassword");

        String newPass = chPwdInfo.getNewpassword();
        checkPasswordParam(newPass, "newPassword");
        // 判断用户是否可用
        User user = userDao.findByUsername(username);
        if (encoder.checkPassword(oldPass, user.getPassword())) {
            user.setPassword(encoder.encodePassword(newPass));
            user.setIsChangePassword(true);
            userDao.save(user);
            logger.info("username = {} changed password success", username);
            return Boolean.TRUE;
        } else {
            logger.info("username ={} change   password failed", username);
            throw new ParamInvalidException(ErrorEnum.INVALID_PRIMARY_PASSWORD);
        }
    }

    /**
     * @see UserService#forgetSendCode(String)
     */
    @Override
    public Boolean forgetSendCode(String username) {
        checkStringParam(username,"username");

        User user = userDao.findByUsername(username);
        String countryCode = user.getContactPhonenum().split("-")[0];
        String contactPhonenum = user.getContactPhonenum().split("-")[1];

        SMS sms = new SMS(contactPhonenum, countryCode);
        Boolean isSend = messageService.sendCode(sms);
        if (isSend) {
            user.setSmsState(1);
        } else {
            user.setSmsState(0);
            userDao.save(user);
            throw new ParamInvalidException(ErrorEnum.NETWORK_EXCEPTION);
        }
        userDao.save(user);
        return isSend;

    }

    /**
     * @see UserService#verifyValidCode(SMSCheckVO, String)
     */
    @Override
    public Boolean verifyValidCode(SMSCheckVO smsCheckVO, String username) {
        checkStringParam(username,"username");
        User user = userDao.findByUsername(username);
        String countryCode = user.getContactPhonenum().split("-")[0];
        String contactPhonenum = user.getContactPhonenum().split("-")[1];

        String code = smsCheckVO.getCode();
        checkCodeParam(code);

        if (user.getSmsState() != 1) {
            throw new ParamInvalidException("please get a smscode first");
        } else {
            SMS sms = new SMS(contactPhonenum, countryCode, code);
            Boolean isCheck = messageService.checkCode(sms);
            if (isCheck) {
                user.setSmsState(2);
            } else {
                user.setSmsState(0);
            }
            userDao.save(user);
            return isCheck;
        }

    }

    /**
     * @see UserService#modifyPassword(ModPassVO, String)
     */
    @Override
    public Boolean modifyPassword(ModPassVO modPassVO, String username) {
        checkUsernameParam(username);
        String password = modPassVO.getPassword();
        checkPasswordParam(password, "password");

        User user = userDao.findByUsername(username);
        if (user == null) {// 用户不存在或者状态为0的
            throw new ParamInvalidException(ErrorEnum.INVALID_USERNAME);
        } else {
            if (user.getSmsState() != 2) {
                throw new ParamInvalidException("please verfify smscode first");
            } else {
                String newPass = encoder.encodePassword(password);
                user.setPassword(newPass);
                user.setSmsState(0);
                user.setIsChangePassword(true);
                user = userDao.save(user);
                logger.info("username={} forget password and modify", username);
                return Boolean.TRUE;
            }
        }
    }

    /**
     * 保存用户的头像信息
     *
     * @param imgVO    {@link ImgVO}
     * @param username 用户名
     * @return {@link User}
     */
    @Override
    public User uploadHeadImg(ImgVO imgVO, String username) {
        String headPicture = imgVO.getHeadPicture();
        if(null == headPicture || headPicture.trim().equals("")){
            throw new ParamInvalidException("headPicture is null");
        }
        String[] str = imgVO.getHeadPicture()
                .split(",");
        if(null == str[0] || null == str[1]){
            throw new ParamInvalidException(ErrorEnum.UPLOAD_FILE_FAILED);
        }
        User user = userDao.findByUsername(username);
        String imgpath =
                String.valueOf(System.currentTimeMillis()) + StringUtil.getRandomString(7) + ".jpg";
        Boolean isokay = ImgUtil.GenerateImage(str[1], localUserProperties.getImgPath() + imgpath);
        if (isokay) {
            String path = localUserProperties.getRealHeadPicture() + imgpath;
            user.setHeadPicture(path);
            user = userDao.save(user);
            return user;
        }
        throw new ParamInvalidException(ErrorEnum.UPLOAD_FILE_FAILED);
    }

    @Override
    public User updateUser(String username, UserUpdateVO userUpdateVO) {
        if (username.equals(userUpdateVO.getUsername())) {
            User user = userDao.findByUsername(username);
            // 更新vos
            user.setAddress(userUpdateVO.getAddress());
            user.setContact(userUpdateVO.getContact());
            user.setEmail(userUpdateVO.getEmail());
            user.setOrganization(userUpdateVO.getOrganization());
            user = userDao.save(user);
            logger.info("update user message={}", user);
            return user;
        } else {
            return null;
        }
    }

    /**
     * 更新用户的订单金额
     *
     * @param username
     *          用户名
     * @param money 金额
     * @param ip ip地址
     * @return {@link User}
     */
    private  User updateLocalUserRestAmouts(String username, Double money,String ip) {
        // 获取本地的剩余金额
        User user = userDao.findByUsername(username);
        Double pre = user.getRestAmounts() ;
        // 计算价格差
        synchronized (pre) {
            Double inter = pre - money;
            Double setInterPrice = vosCustomerProperties.getLimitMoney();
            if (inter <= setInterPrice) {// 如果价格小于设定的limit美元
                logger.info("username={},less than limit money={},dont't record", username,setInterPrice);
            } else {
                // 插入消费记录并更新账户余额
                Double result = consumptionDao.insertConsumptionInfoProc(username,
                        localUserProperties.getTelBillOpt(), inter);
                if (result.compareTo(0.0) == 1) {
                    user.setRestAmounts(result);
                    logger.info("username={},bigger than limit money = {},restamouts={}",username, setInterPrice, user.getRestAmounts());
                    logService.saveLog(username,"Settlement amount",ip,true,"amount bigger than limit money "+setInterPrice);
                } else {
                    logger.info("update user ingfo from vos failed");
                }
            }
        }
        return user;
    }


    @Override
    public Boolean sendValidCode(SMSSendVO SMSSendVO) {

        return null;
    }

    @Override
    public List<User> findUserByRestAmountsLessThanLimit() {
        return userDao.findByRestAmountsLessThanEqualAndAvailableAmountsAlarm(
                localUserProperties.getAlarmMoney(), 1);
    }

    @Override
    public User isOpenAlarm(String username, AlarmVO alarmVO) {
        Integer isalarm = alarmVO.getIsalarm();
        if (null == isalarm) {
            throw new ParamInvalidException("isalarm is null");
        }
        User user = userDao.findByUsername(username);
        user.setAvailableAmountsAlarm(isalarm);
        user = userDao.save(user);
        logger.info("update user account isalarm success ={}", user);
        return user;
    }

    /**
     * 判断vos的账户是否已经被注册
     *
     * @param username 用户名
     * @return 检查结果, false用户名不可用, true 用户名可用
     */
    private Boolean isVosUsernameAvailable(String username) {
        // 判断用户是否在vos注册
        Object object = userVosDao.getVosCustomer(new UserRequest(new String[]{username}));
        if (object instanceof Customer) {
            Customer customer = (Customer) object;
            if (customer.getAccount() != null) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public User getUserByUsername(String username) {
        return userDao.findByUsername(username);
    }

}
